import { loadRefreshToken } from '@/services/user'
import { Modal } from 'ant-design-vue'
import store from '@/store'
import { LOGIN, REFRESH_TOKEN, LOGOUT, CAPTCHA } from '@/services/api'
import storage from 'store'
import { ACCESS_TOKEN, ACCESS_REFRESH_TOKEN } from '@/store/mutation-types'
import { axios } from '@/utils/request'
// 请求队列
const requestQueue = {
  // 请求列表，存储刷新 token 期间发起的请求
  list: [],
  isRefreshing: false,
  // 添加请求
  add(config, resolve, reject) {
    this.list.push((newToken) => {
      if (newToken) {
        config.headers['Access-Token'] = newToken
        // _retry标记是否需要重新发起请求，待token刷新后，继续请求即可，不带该属性token刷新后需要重新请求
        config._retry ? resolve(config) : resolve(axios(config))
      } else { // token不为真 表示 token 获取失败，清理队列请求的 Promise，避免内存堆积
        return reject({ status: 200, data: { code: 401 }, message: 'token已失效,请重新登录' })
      }
    })
  },
  // 执行队列
  execute(token) {
    let fn
    // eslint-disable-next-line
    while (fn = this.list.shift()) {
      fn(token)
    }
  },
  // 清空队列
  clear() {
    this.execute()
  }
}

function directLogin() { // 退出重新登录
  try {
    const path = window.document.location.pathname
    if (path !== '/' && path.indexOf('/login') === -1) {
      window.location.reload()
    }
  } catch (e) {
    window.location.reload()
  }
}

function loginExpired() {
  setTimeout(() => {
    const path = window.document.location.pathname
    if (path !== '/' && path.indexOf('/login') === -1) {
      Modal.error({
        title: '登录已过期',
        content: '很抱歉，登录已过期，请重新登录',
        okText: '重新登录',
        mask: false,
        onOk: () => {
          store.dispatch('account/Logout').then(() => {
            directLogin()
          })
        }
      })
    }
  }, 200)
}

function handleByRefreshStatus(config, type = 'response') {
  return new Promise((resolve, reject) => {
    const status = requestQueue.refreshTokenStatus
    if (type === 'request') {
      // 判断是否正在刷新 token
      if (!status) {
        resolve(config)
      } else {
        requestQueue.add(config, resolve, reject)
      }
    } else {
      // 将请求添加到队列中，待刷新完成后执行队列
      requestQueue.add(config, resolve, reject)
      // 判断 token 刷新状态
      if (!status) {
        requestQueue.refreshTokenStatus = true
        const refreshToken = storage.get(ACCESS_REFRESH_TOKEN)
        const token = storage.get(ACCESS_TOKEN)
        loadRefreshToken({
          refreshToken: refreshToken,
          token: token
        }).then(res => {
          requestQueue.refreshTokenStatus = false
          const code = res.result.code || 200
          if (code === 200) {
            store.commit('account/setToken', res.result.token)
            store.commit('account/setRefreshToken', res.result.refreshToken)
            requestQueue.execute(res.result.token)
          } else {
            requestQueue.clear()
            loginExpired()
          }
        }).catch(() => {
          requestQueue.refreshTokenStatus = false
          requestQueue.clear()
          loginExpired()
        })
      }
    }
  })
}

const respError = {
  onFulfilled(response, options) {
    const { message } = options
    if (response.status !== 200) {
      message.error(response.data.message || response.message)
    }
    return response
  },
  onRejected(error, options) {
    const { response } = error
    const { message } = options
    if (response && response.status !== 200) {
      console.error(response)
      message.error(response.data.message || response.message)
    }
    return Promise.reject(response)
  }
}

const resp200 = {
  onFulfilled(response, options) {
    if (response.status === 200) {
      // 请求成功
      if (response.data.code === 200) {
        return response.data
      }
      const { config } = response
      // refresh_token请求
      if (config.url === REFRESH_TOKEN) {
        return response.data
      }

      if (response.data.code === 401) {
        return handleByRefreshStatus(config)
      }
      const { message } = options
      // 不需要统一处理提示的可以设置_message为false
      config._message !== false && message.error(response.data.message)
      return response.data
    }
    return response.data
  }
}

const reqCommon = {
  /**
   * 发送请求之前做些什么
   * @param config axios config
   * @param options 应用配置 包含: {router, i18n, store, message}
   * @returns {*}
   */
  onFulfilled(config) {
    const token = storage.get(ACCESS_TOKEN)
    const url = [LOGIN, REFRESH_TOKEN, LOGOUT, CAPTCHA]// 免除校验token路径

    if (url.includes(config.url)) {
      return config
    }
    // 如果 token 存在
    // 让每个请求携带自定义 token 请根据实际情况自行修改
    if (token) {
      config.headers['Access-Token'] = token
      return handleByRefreshStatus(config, 'request')
    }
    config._retry = true
    return handleByRefreshStatus(config)
  },
  /**
   * 请求出错时做点什么
   * @param error 错误对象
   * @param options 应用配置 包含: {router, i18n, store, message}
   * @returns {Promise<never>}
   */
  onRejected(error, options) {
    const { message } = options
    message.error(error.message)
    return Promise.reject(error)
  }
}

export default {
  request: [reqCommon], // 请求拦截
  response: [respError, resp200] // 响应拦截
}
